package com.jtny.nytb.dataparam.service.serviceImpl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jtny.component.core.util.PageUtils;
import com.jtny.component.entity.PageData;
import com.jtny.component.enums.GenericStatusEnum;
import com.jtny.component.exception.ServiceException;
import com.jtny.component.util.BeanUtils;
import com.jtny.nytb.config.coderule.dto.ConfigRuleManagementDTO;
import com.jtny.nytb.config.coderule.dto.ConfigRuleManagementPageDTO;
import com.jtny.nytb.config.coderule.dto.ConfigRuleParamRelationDTO;
import com.jtny.nytb.config.coderule.dto.ConfigRuleSequenceNumberDTO;
import com.jtny.nytb.config.coderule.errorcode.RuleErrorCodeEnum;
import com.jtny.nytb.dataparam.service.ConfigRuleManagementService;
import com.jtny.nytb.equipment.dao.coderule.ConfigRuleManagementDAO;
import com.jtny.nytb.equipment.dao.coderule.ConfigRuleParamRelationDAO;
import com.jtny.nytb.equipment.domain.coderule.ConfigRuleManagementDO;
import com.jtny.nytb.equipment.domain.coderule.ConfigRuleParamRelationDO;
import com.jtny.nytb.equipment.utils.RandomData;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Optional;
import java.util.Random;
import java.util.stream.Collectors;

@Service
@AllArgsConstructor
public class ConfigRuleManagementServiceImpl implements ConfigRuleManagementService {

    private ConfigRuleManagementDAO ruleManagementDAO;
    private ConfigRuleParamRelationDAO ruleParamRelationDAO;
    private ConfigRuleSequenceNumberServiceImpl ruleSequenceNumberService;

    /**
     * 保存规则管理数据
     * @param configRuleManagementDTO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ConfigRuleManagementDTO save(ConfigRuleManagementDTO configRuleManagementDTO) {
        // 判定标识和名称是否重复。
        QueryWrapper<ConfigRuleManagementDO> wrapper = new QueryWrapper<>();
        wrapper.eq("sign", configRuleManagementDTO.getSign());
        wrapper.eq("name", configRuleManagementDTO.getName());
        List<ConfigRuleManagementDO> configRuleManagementDOS = ruleManagementDAO.selectList(wrapper);
        if (CollUtil.isNotEmpty(configRuleManagementDOS)){
            throw new ServiceException(RuleErrorCodeEnum.PARAM_NAME_OR_SIGN_REPEAT.getErrorCode(), RuleErrorCodeEnum.PARAM_NAME_OR_SIGN_REPEAT.getErrorMessage());
        }
        // 获取单据规则基本数据
        ConfigRuleManagementDO configRuleManagementDO = BeanUtils.copyToObject(configRuleManagementDTO, ConfigRuleManagementDO.class);
        ruleManagementDAO.insert(configRuleManagementDO);
        // 获取单据的关联规则
        List<ConfigRuleParamRelationDO> relationDOList = BeanUtils.copyToList(configRuleManagementDTO.getConfigRuleParamRelationList(), ConfigRuleParamRelationDO.class);
        // 如果没有关联规则，则返回。
        if (CollUtil.isEmpty(relationDOList)){
            return configRuleManagementDTO;
        }
        List<ConfigRuleParamRelationDO> errorRealtions = relationDOList.stream().filter(obj -> obj.getId() != null && obj.getId() != 0).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(errorRealtions)){
            throw new ServiceException(RuleErrorCodeEnum.PARAM_PARAM_IS_ERROR.getErrorCode(), RuleErrorCodeEnum.PARAM_PARAM_IS_ERROR.getErrorMessage());
        }
        // 当规则存在，则设置规则id到单据中。
        relationDOList.forEach(configRuleParamRelationDO -> {
            configRuleParamRelationDO.setRuleId(configRuleManagementDO.getId());
        });
        ruleParamRelationDAO.insertBatch(relationDOList);
        return configRuleManagementDTO;
    }

    /**
     * 通过规则id获取单据数据
     * @param ruleId
     * @return
     */
    @Override
    public ConfigRuleManagementDTO queryById(Long ruleId) {
        // 获取单据基本信息
        com.jtny.nytb.equipment.domain.coderule.ConfigRuleManagementDO configRuleManagementDO = ruleManagementDAO.selectById(ruleId);
        // 获取单据关联的规则信息
        QueryWrapper<ConfigRuleParamRelationDO> wrapper = new QueryWrapper<>();
        wrapper.eq("rule_id", ruleId);
        wrapper.orderByAsc("sort");
        List<ConfigRuleParamRelationDO> configRuleParamRelationDOList = ruleParamRelationDAO.selectList(wrapper);
        // 将规则管理DO对象转为DTO对象
        ConfigRuleManagementDTO configRuleManagementDTO = BeanUtils.copyToObject(configRuleManagementDO, ConfigRuleManagementDTO.class);
        List<ConfigRuleParamRelationDTO> configRuleParamRelationDTOList = BeanUtils.copyToList(configRuleParamRelationDOList, ConfigRuleParamRelationDTO.class);
        configRuleManagementDTO.setConfigRuleParamRelationList(configRuleParamRelationDTOList);
        return configRuleManagementDTO;
    }

    /**
     * 更新规则数据
     * @param configRuleManagementDTO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ConfigRuleManagementDTO update(ConfigRuleManagementDTO configRuleManagementDTO) {
        // 检查是否重复
        findRepeatManagement(configRuleManagementDTO);

        // 第一步：更新规则管理基础数据
        ConfigRuleManagementDO configRuleManagementDO = BeanUtils.copyToObject(configRuleManagementDTO, ConfigRuleManagementDO.class);
        ruleManagementDAO.updateById(configRuleManagementDO);
        // 获取上次的规则，并删除
        QueryWrapper<ConfigRuleParamRelationDO> wrapper = new QueryWrapper<>();
        wrapper.eq("rule_id", configRuleManagementDO.getId());
        ruleParamRelationDAO.delete(wrapper);
        // 保存本次规则
        List<ConfigRuleParamRelationDTO> configRuleParamRelationList = configRuleManagementDTO.getConfigRuleParamRelationList();
        if (CollectionUtil.isEmpty(configRuleParamRelationList)){
            return configRuleManagementDTO;
        }
        List<ConfigRuleParamRelationDO> configRuleParamRelationDOList = BeanUtils.copyToList(configRuleParamRelationList, ConfigRuleParamRelationDO.class);
        configRuleParamRelationDOList.forEach(param -> {
            param.setRuleId(configRuleManagementDO.getId());
            param.setCreatorId(configRuleManagementDTO.getLastUpdaterId());
            param.setCreateTime(configRuleManagementDTO.getLastUpdateTime());
            param.setCreatorName(configRuleManagementDTO.getLastUpdaterName());
            param.setLastUpdaterId(configRuleManagementDTO.getLastUpdaterId());
            param.setLastUpdateTime(configRuleManagementDTO.getLastUpdateTime());
            param.setLastUpdaterName(configRuleManagementDTO.getLastUpdaterName());
        });
        ruleParamRelationDAO.insertBatch(configRuleParamRelationDOList);
        return configRuleManagementDTO;
    }

    private void findRepeatManagement(ConfigRuleManagementDTO configRuleManagementDTO) {
        ConfigRuleManagementDO configRuleManagementDO1 = ruleManagementDAO.selectById(configRuleManagementDTO.getId());
        if (configRuleManagementDO1 == null){
            throw new ServiceException(RuleErrorCodeEnum.PARAM_ID_NOT_FIND.getErrorCode(), RuleErrorCodeEnum.PARAM_ID_NOT_FIND.getErrorMessage());
        }

        if (configRuleManagementDO1.getName().equals(configRuleManagementDTO.getName()) &&
                configRuleManagementDO1.getSign().equals(configRuleManagementDTO.getSign())){
            return;
        }
        QueryWrapper<ConfigRuleManagementDO> ruleWrapper = new QueryWrapper<>();
        if (!configRuleManagementDO1.getName().equals(configRuleManagementDTO.getName())) {
            ruleWrapper.eq("name", configRuleManagementDTO.getName());
        }
        if (!configRuleManagementDO1.getSign().equals(configRuleManagementDTO.getSign())){
            ruleWrapper.eq("sign", configRuleManagementDTO.getSign());
        }
        ruleWrapper.eq("status", 0);
        List<ConfigRuleManagementDO> configRuleManagementDOS = ruleManagementDAO.selectList(ruleWrapper);
        if (CollectionUtil.isNotEmpty(configRuleManagementDOS)){
            throw new ServiceException(RuleErrorCodeEnum.PARAM_NAME_OR_SIGN_REPEAT.getErrorCode(), RuleErrorCodeEnum.PARAM_NAME_OR_SIGN_REPEAT.getErrorMessage());
        }
    }

    /**
     * 删除当前规则
     * @param ruleId
     * @return
     */
    @Override
    public ConfigRuleManagementDTO delete(Long ruleId) {
        ConfigRuleManagementDO configRuleManagementDO = ruleManagementDAO.selectById(ruleId);
        configRuleManagementDO.setStatus(9);
        ruleManagementDAO.updateById(configRuleManagementDO);
        ConfigRuleManagementDTO configRuleManagementDTO = BeanUtils.copyToObject(configRuleManagementDO, ConfigRuleManagementDTO.class);
        return configRuleManagementDTO;
    }

    /**
     * 分页查询。
     * @param configRuleManagementPageDTO
     * @return
     */
    @Override
    public PageData<ConfigRuleManagementDTO> queryPage(ConfigRuleManagementPageDTO configRuleManagementPageDTO) {
        QueryWrapper<ConfigRuleManagementDO> wrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(configRuleManagementPageDTO.getSign())){
            wrapper.eq("sign", configRuleManagementPageDTO.getSign());
        }
        if (StringUtils.isNotBlank(configRuleManagementPageDTO.getName())){
            wrapper.like("name", configRuleManagementPageDTO.getName());
        }
        Optional.ofNullable(configRuleManagementPageDTO.getIdList())
                .ifPresent(list -> wrapper.in("id", list));
        wrapper.eq("status", GenericStatusEnum.NORMAL.getValue());
        wrapper.orderByDesc("id");
        Page<ConfigRuleManagementDO> page = Page.of(configRuleManagementPageDTO.getPageNo(), configRuleManagementPageDTO.getPageSize());
        PageData<ConfigRuleManagementDO> pageDataForDO = PageUtils.getPageData(ruleManagementDAO.selectPage(page, wrapper), configRuleManagementPageDTO);
        PageData<ConfigRuleManagementDTO> configRuleManagementDTOPageData = pageDataForDO.transformData(ConfigRuleManagementDTO.class);
        configRuleManagementDTOPageData.getData().forEach(obj -> {
            QueryWrapper<ConfigRuleParamRelationDO> wrapper1 = new QueryWrapper<>();
            wrapper1.eq("rule_id", obj.getId());
            List<ConfigRuleParamRelationDO> configRuleParamRelationDOList = ruleParamRelationDAO.selectList(wrapper1);
            List<ConfigRuleParamRelationDTO> configRuleParamRelationDTOList = BeanUtils.copyToList(configRuleParamRelationDOList, ConfigRuleParamRelationDTO.class);
            obj.setConfigRuleParamRelationList(configRuleParamRelationDTOList);
        });
        return configRuleManagementDTOPageData;
    }

    /**
     * 根据标记进行获取
     * @param code
     * @return
     */
    @Override
    public ConfigRuleManagementDTO queryBycode(String code) {
        // 获取单据基本信息
        QueryWrapper<ConfigRuleManagementDO> menagementWrapper = new QueryWrapper<>();
        menagementWrapper.eq("sign", code);
        menagementWrapper.eq("status", 0);
        ConfigRuleManagementDO configRuleManagementDO = ruleManagementDAO.selectOne(menagementWrapper);
        if (configRuleManagementDO == null){
            return null;
        }
        // 获取单据关联的规则信息
        QueryWrapper<ConfigRuleParamRelationDO> wrapper = new QueryWrapper<>();
        wrapper.eq("rule_id", configRuleManagementDO.getId());
        wrapper.orderByAsc("sort");
        List<ConfigRuleParamRelationDO> configRuleParamRelationDOList = ruleParamRelationDAO.selectList(wrapper);
        // 将规则管理DO对象转为DTO对象
        ConfigRuleManagementDTO configRuleManagementDTO = BeanUtils.copyToObject(configRuleManagementDO, ConfigRuleManagementDTO.class);
        List<ConfigRuleParamRelationDTO> configRuleParamRelationDTOList = BeanUtils.copyToList(configRuleParamRelationDOList, ConfigRuleParamRelationDTO.class);
        configRuleManagementDTO.setConfigRuleParamRelationList(configRuleParamRelationDTOList);
        return configRuleManagementDTO;
    }

    /**
     * 查询最新的规则
     * @return
     */
    @Override
    public ConfigRuleManagementDTO queryLast() {
        // 获取单据基本信息
        QueryWrapper<ConfigRuleManagementDO> menagementWrapper = new QueryWrapper<>();
        menagementWrapper.eq("status", 0);
        menagementWrapper.orderByDesc("create_time");
        List<ConfigRuleManagementDO> configRuleManagementDOS = ruleManagementDAO.selectList(menagementWrapper);
        if (CollectionUtil.isEmpty(configRuleManagementDOS)){
            return null;
        }
        ConfigRuleManagementDO configRuleManagementDO = configRuleManagementDOS.get(0);
        ConfigRuleManagementDTO configRuleManagementDTO = BeanUtils.copyToObject(configRuleManagementDO, ConfigRuleManagementDTO.class);
        // 获取规则详情
        Long id = configRuleManagementDTO.getId();
        QueryWrapper<ConfigRuleParamRelationDO> paramWrapper = new QueryWrapper<>();
        paramWrapper.eq("rule_id", id);
        List<ConfigRuleParamRelationDO> configRuleParamRelationDOS = ruleParamRelationDAO.selectList(paramWrapper);
        List<ConfigRuleParamRelationDTO> configRuleParamRelationDTOS = BeanUtils.copyToList(configRuleParamRelationDOS, ConfigRuleParamRelationDTO.class);
        configRuleManagementDTO.setConfigRuleParamRelationList(configRuleParamRelationDTOS);
        return configRuleManagementDTO;
    }

    /**
     *  查询编号
     * @param code 编号规则code
     * @return
     */
    @Override
    public String queryCodeBycode(String code, String superiorCode) {
        ConfigRuleManagementDTO configRuleManagementDTO = queryBycode(code);
        StringBuilder codeString = new StringBuilder();
        if (configRuleManagementDTO == null){
            // 如果查询规则不存在，需要获取最后一条规则的顺序号。判定改规则中是否含有顺序号，如果没有进行
            ConfigRuleManagementDTO configRuleManagementDTO1 = queryLast();
            List<ConfigRuleParamRelationDTO> configRuleParamRelationList = configRuleManagementDTO1.getConfigRuleParamRelationList();
            List<ConfigRuleParamRelationDTO> sequenceNumber = configRuleParamRelationList.stream().filter(obj -> obj.getCode().equals("SequenceNumber")).collect(Collectors.toList());
            // 存在顺序号，同时顺序号存放在最后面，
            if (CollectionUtil.isNotEmpty(sequenceNumber) && sequenceNumber.get(0).getSort() == configRuleParamRelationList.size()){
                generateRuleCode(configRuleParamRelationList, codeString, superiorCode);
            }else{
                for (int i = 0; i < 5; i++) {
                    String str = RandomData.RANDOMUPPERCASEANDLOWERCASELETTERSANDNUMBERS.getMessage();
                    Random random = new Random();
                    int randomIndex = random.nextInt(str.length());
                    char randomChar = str.charAt(randomIndex);
                    codeString.append(randomChar);
                }
            }
            return codeString.toString();
        }
        List<ConfigRuleParamRelationDTO> configRuleParamRelationList = configRuleManagementDTO.getConfigRuleParamRelationList();
        generateRuleCode(configRuleParamRelationList, codeString, superiorCode);
        return codeString.toString();
    }

    /**
     * 按名称存在
     *
     * @param nameList 名称列表
     * @return {@link List}<{@link String}>
     */
    @Override
    public List<String> existCodeRuleByName(List<String> nameList) {
        if(CollUtil.isNotEmpty(nameList)){
            LambdaQueryWrapper<ConfigRuleManagementDO> wrapper = Wrappers.<ConfigRuleManagementDO>lambdaQuery()
                    .in(ConfigRuleManagementDO::getName, nameList)
                    .ne(ConfigRuleManagementDO::getStatus, GenericStatusEnum.DELETED.getValue());
            List<ConfigRuleManagementDO> configRuleManagementList = ruleManagementDAO.selectList(wrapper);
            return configRuleManagementList.stream().map(ConfigRuleManagementDO::getName).collect(Collectors.toList());
        }
        return CollUtil.newArrayList();
    }

    @Override
    public Boolean saveBatchCodeRule(List<ConfigRuleManagementDTO> toSaveList) {
        if (CollectionUtil.isNotEmpty(toSaveList)){
            for (ConfigRuleManagementDTO configRuleManagementDTO : toSaveList) {
                // 获取单据规则基本数据
                ConfigRuleManagementDO configRuleManagementDO = BeanUtils.copyToObject(configRuleManagementDTO, ConfigRuleManagementDO.class);
                ruleManagementDAO.insert(configRuleManagementDO);

                List<ConfigRuleParamRelationDTO> configRuleParamRelationList = configRuleManagementDTO.getConfigRuleParamRelationList();
                // 当规则存在，则设置规则id到单据中。
                List<ConfigRuleParamRelationDO> toSaveParamList = configRuleParamRelationList.stream().map(relationDTO -> {
                    ConfigRuleParamRelationDO configRuleParamRelationDO = BeanUtils.copyToObject(relationDTO, ConfigRuleParamRelationDO.class);
                    configRuleParamRelationDO.setRuleId(configRuleManagementDO.getId());
                    return configRuleParamRelationDO;
                }).collect(Collectors.toList());
                ruleParamRelationDAO.insertBatch(toSaveParamList);
            }
        }
        return Boolean.TRUE;
    }

    /**
     * 生产编码
     * @param configRuleParamRelationList
     * @param codeString
     */
    private void generateRuleCode(List<ConfigRuleParamRelationDTO> configRuleParamRelationList, StringBuilder codeString,
                                  String superiorCode) {

        for (ConfigRuleParamRelationDTO relationDTO : configRuleParamRelationList) {
            // 对于展示值，将值存入在code
            if (relationDTO.getShowName().equals(0)){
                codeString.append(relationDTO.getValue());
            }else if ("SuperiorCode".equals(relationDTO.getCode())){
                // 展示上级编码
                if (StringUtils.isBlank(superiorCode)){
                    continue;
                }
                codeString.append(superiorCode);
            }else if (relationDTO.getDigit() != null && relationDTO.getDigit() > 0) {
                StringBuilder randomString = new StringBuilder();
                if ("SequenceNumber".equals(relationDTO.getCode())){
                    // 获取当前顺序号。
                    getSequenceNumber(superiorCode, relationDTO, randomString);
                }else{
//                    展示随机数
                    getRandomNumber(relationDTO, randomString);
                }
                codeString.append(randomString.toString());
            } else if (relationDTO.getDigit() == null || 0 == relationDTO.getDigit()) {
                // 获取当前随机时间
                LocalDate localDate = LocalDate.now();
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern(relationDTO.getCode());
                String formateString = localDate.format(formatter);
                codeString.append(formateString);
            }
        }
    }

    /**
     * 获取顺序号
     * @param superiorCode 父标签的值
     * @param relationDTO 关联对象
     * @param randomString 顺序号字符串。
     */
    private void getSequenceNumber(String superiorCode, ConfigRuleParamRelationDTO relationDTO, StringBuilder randomString) {
        String lastcode = superiorCode;
        if (StringUtils.isBlank(superiorCode)){  // 判定父标签是否存在，如果存在则获取父标签的数据，作为查询顺序号的条件之一。
            lastcode = "";
        }
        ConfigRuleSequenceNumberDTO configRuleSequenceNumberDTO = ruleSequenceNumberService.querylastNumber(lastcode, relationDTO.getValue());
        String numstr = configRuleSequenceNumberDTO.getSequenceNumber() + "";
        int length = numstr.length();

     /*   if (relationDTO.getDigit() == null){
            throw new ServiceException()
        }*/
        for (int i = 0; i < relationDTO.getDigit() - length; i++) {
            numstr = "0" + numstr;
        }
        randomString.append(numstr);
    }

    /**
     * 获取随机数。
     * @param relationDTO  关联对象
     * @param randomString 随机数字符串
     */
    private static void getRandomNumber(ConfigRuleParamRelationDTO relationDTO, StringBuilder randomString) {
        System.out.println("随机数："+ relationDTO.getCode());
        Random random = new Random();
        for (int i = 0; i < relationDTO.getDigit(); i++) {
            String str;
            if (RandomData.RANDOMLOWERCASELETTERS.getCode().equals(relationDTO.getCode())){
                str = RandomData.RANDOMLOWERCASELETTERS.getMessage();
            } else if (RandomData.RANDOMUPPERCASELETTERS.getCode().equals(relationDTO.getCode())){
                str = RandomData.RANDOMUPPERCASELETTERS.getMessage();
            } else if (RandomData.RANDOMNUMBERS.getCode().equals(relationDTO.getCode())) {
                str = RandomData.RANDOMNUMBERS.getMessage();
            } else if (RandomData.RANDOMLOWERCASELETTERSANDNUMBERS.getCode().equals(relationDTO.getCode())) {
                str = RandomData.RANDOMLOWERCASELETTERSANDNUMBERS.getMessage();
            } else if (RandomData.RANDOMUPPERCASELETTERSANDNUMBERS.getCode().equals(relationDTO.getCode())) {
                str = RandomData.RANDOMUPPERCASELETTERSANDNUMBERS.getMessage();
            } else if (RandomData.RANDOMUPPERCASEANDLOWERCASELETTERS.getCode().equals(relationDTO.getCode())) {
                str = RandomData.RANDOMUPPERCASEANDLOWERCASELETTERS.getMessage();
            } else if (RandomData.RANDOMUPPERCASEANDLOWERCASELETTERSANDNUMBERS.getCode().equals(relationDTO.getCode())) {
                str = RandomData.RANDOMUPPERCASEANDLOWERCASELETTERSANDNUMBERS.getMessage();
            }else{
                throw new ServiceException("随机数据规则有误", "B020080002");
            }
            int randomIndex = random.nextInt(str.length());
            char randomChar = str.charAt(randomIndex);
            randomString.append(randomChar);
        }
    }

}

